from __future__ import annotations

from dataclasses import dataclass
from typing import List, Optional
from datetime import datetime, timedelta
import asyncio
import random

from .schemas import RecordOut, RecordDetailOut, ResultPoint


@dataclass
class Storage:
    # placeholder for real DB connection
    _lock: asyncio.Lock
    _records: List[RecordDetailOut]

    async def list_records(
        self, device_id: Optional[str], class_label: Optional[str], from_ts: Optional[str], to_ts: Optional[str]
    ) -> List[RecordOut]:
        def in_range(dt: datetime) -> bool:
            if from_ts:
                try:
                    if dt < datetime.fromisoformat(from_ts):
                        return False
                except Exception:
                    pass
            if to_ts:
                try:
                    if dt > datetime.fromisoformat(to_ts):
                        return False
                except Exception:
                    pass
            return True

        result: List[RecordOut] = []
        for r in self._records:
            if device_id and r.device_id != device_id:
                continue
            if class_label and r.class_label != class_label:
                continue
            if not in_range(r.started_at):
                continue
            result.append(
                RecordOut(
                    record_id=r.record_id,
                    device_id=r.device_id,
                    started_at=r.started_at,
                    ended_at=r.ended_at,
                    location=r.location,
                    tags=r.tags,
                    summary=r.summary,
                    class_label=r.class_label,
                    confidence=r.confidence,
                )
            )
        return sorted(result, key=lambda x: x.started_at, reverse=True)

    async def get_record(self, record_id: str) -> RecordDetailOut:
        for r in self._records:
            if r.record_id == record_id:
                return r
        raise KeyError("record not found")

    async def create_demo_record(self) -> RecordOut:
        async with self._lock:
            rid = f"rec_{len(self._records) + 1:04d}"
            now = datetime.utcnow()
            device = random.choice(["devA", "devB"]) 
            label = random.choice(["normal", "warning", "alert"]) 
            conf = round(random.uniform(0.7, 0.99), 2)
            series = [
                ResultPoint(t=i * 0.1, metric_name="rms", value=abs(random.gauss(0, 1)) * (1.0 + 0.2 * (i % 10)))
                for i in range(300)
            ]
            rec = RecordDetailOut(
                record_id=rid,
                device_id=device,
                started_at=now - timedelta(seconds=30),
                ended_at=now,
                location="loc-1",
                tags=["demo"],
                summary="demo record",
                class_label=label,
                confidence=conf,
                series=series,
            )
            self._records.append(rec)
            return RecordOut(
                record_id=rec.record_id,
                device_id=rec.device_id,
                started_at=rec.started_at,
                ended_at=rec.ended_at,
                location=rec.location,
                tags=rec.tags,
                summary=rec.summary,
                class_label=rec.class_label,
                confidence=rec.confidence,
            )


_storage: Optional[Storage] = None


async def init_db() -> None:
    global _storage
    if _storage is None:
        _storage = Storage(asyncio.Lock(), [])
        # Seed some demo records
        for _ in range(5):
            await _storage.create_demo_record()


async def get_storage() -> Storage:
    assert _storage is not None
    return _storage